﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Marbles.Core.Connectors;
using System.IO.Compression;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Web;
using Marbles.Core.Content;
using Marbles.Core.Content.Sites;

namespace Marbles.Core.Content.Assets
{
    public class Asset
    {

        public string SiteId { get { return _siteid; } }
        public string AssetId { get { return _assetid; } }
        public string Filename { get { return _filename; } set { _filename = value; } }
        public string Extension { get { return _extension; } set { _extension = value; } }
        public string ContentType { get { return _contenttype.ToLower(); } set { _contenttype = value.ToLower(); } }
        public string IconUrl { get { return ContentTypes.GetIconUrl(_contenttype); } }
        public string ThumbnailUrl { get { return "Thumbnail.axd?id=" + _assetid; } }
        public string AssetUrl { get { return "Asset.axd?id=" + _assetid; } }
        public string DownloadPath { get { return GetDownloadPath(); } }
        public string ApplicationPath { get { return HttpContext.Current.Server.MapPath(DownloadPath); } }
        public string FullFilename { get { return Filename + Extension; } }
        public bool IsImage { get { return ContentType.StartsWith("image/"); } }
        public bool IsVideo { get { return ContentType.StartsWith("video/"); } }
        public string Compression { get { return _compression; } }
        public DateTime LastAccess { get { return _LastAccess; } }
        public string LastAccessDate { get { return _LastAccess.Year > 1980 ? _LastAccess.ToString("dd/MM/yyyy HH:mm:ss") : ""; } }

        private DateTime _LastAccess = Marbles.Core.Connectors.DataConnection.MinimumDateTime;
        private string _compression = string.Empty;
        private string _siteid = string.Empty;
        private string _assetid = string.Empty;
        private string _filename = string.Empty;
        private string _extension = string.Empty;
        private string _contenttype = string.Empty;

        public Asset()
        {
            _compression = string.Empty;
            _siteid = string.Empty;
            _assetid = string.Empty;
            _filename = string.Empty;
            _extension = string.Empty;
            _contenttype = string.Empty;
        }

        public Asset(string SiteId, string AssetId)
            : this()
        {
            DataConnection dbc = new DataConnection();
            Command cmd = new Command("SELECT * FROM assets WHERE siteid = @siteid AND assetid = @assetid");
            _siteid = SiteId;
            _assetid = AssetId;
            cmd.AddParameter("@siteid", SiteId);
            cmd.AddParameter("@assetid", AssetId);
            DataTable dt = dbc.FetchDataTable(cmd);
            if (dt.Rows.Count > 0)
            {
                _LastAccess = Convert.ToDateTime(dt.Rows[0]["lastaccess"]);
                _contenttype = dt.Rows[0]["contenttype"].ToString();
                _extension = dt.Rows[0]["extension"].ToString();
                _filename = dt.Rows[0]["filename"].ToString();
                _compression = dt.Rows[0]["compression"].ToString().ToLower();
            }
        }

        internal Asset(DataRow row)
            : this()
        {
            _LastAccess = Convert.ToDateTime(row["lastaccess"]);
            _siteid = row["siteid"].ToString();
            _assetid = row["assetid"].ToString();
            _filename = row["filename"].ToString();
            _extension = row["extension"].ToString();
            _contenttype = row["contenttype"].ToString();
            _compression = row["compression"].ToString().ToLower();
        }

        private string GetDownloadPath()
        {
            SiteDefinition web = new Sites.SiteDefinition(_siteid);
            string path = web.ResourceDirectory + _assetid;
            return path;
        }

        public void Download(bool attachment)
        {
            Download(HttpContext.Current.Response, attachment);
        }

        public void Download(HttpResponse response, bool attachment)
        {
            response.ContentType = _contenttype;

            if (attachment)
            {
                response.AddHeader("content-disposition", string.Format("attachment;filename={0}", _filename + _extension));
            }
            else
            {
                response.AddHeader("content-disposition", string.Format("inline;filename={0}", _filename + _extension));
            }

            FileStream fs = new FileStream(ApplicationPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

            if (!CompressionEnabled)
            {
                DownloadFileFromStream(response, fs);
            }
            else
            {
                Stream compressStream = GetCompressionStream(fs, CompressionMode.Decompress);
                DownloadFileFromStream(response, compressStream);
                compressStream.Close();
            }

            fs.Close();
            response.Flush();
        }

        public Stream GetStream()
        {
            FileStream fs = new FileStream(ApplicationPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            if (!CompressionEnabled) { return fs; }
            return GetCompressionStream(fs, CompressionMode.Decompress);
        }

        public void DownloadFileFromStream(HttpResponse Response, Stream iStream)
        {
            byte[] buffer = new Byte[10000];
            int length = 1;
            long dataToRead = 0;

            //dataToRead = iStream.Length;

            while (length > 0)
            {
                if (Response.IsClientConnected)
                {
                    length = iStream.Read(buffer, 0, 10000);
                    Response.OutputStream.Write(buffer, 0, length);
                    Response.Flush();
                    buffer = new Byte[10000];
                    dataToRead = dataToRead - length;
                }
                else
                {
                    dataToRead = -1;
                }
            }
        }

        public static Asset CreateNew(string SiteId)
        {
            Asset item = new Asset();
            item._siteid = SiteId;
            item._assetid = Guid.NewGuid().ToString();
            return item;
        }

        public static Asset CreateNew(Sites.SiteDefinition Web)
        {
            return CreateNew(Web.SiteId);
        }

        public void Update()
        {
            DataConnection dbc = new DataConnection();
            Command cmd = new Command("UPDATE assets SET compression = @compression, filename = @filename, extension = @extension, contenttype = @contenttype WHERE siteid = @siteid AND assetid = @assetid");
            cmd.AddParameter("@compression", _compression);
            cmd.AddParameter("@filename", _filename);
            cmd.AddParameter("@extension", _extension);
            cmd.AddParameter("@contenttype", _contenttype);
            cmd.AddParameter("@siteid", _siteid);
            cmd.AddParameter("@assetid", _assetid);
            dbc.ExecuteCommand(cmd);
        }

        public void Insert()
        {
            DataConnection dbc = new DataConnection();
            Command cmd = new Command("INSERT INTO assets (lastaccess,siteid, assetid, filename, extension, contenttype, compression) VALUES (@lastaccess,@siteid, @assetid, @filename, @extension, @contenttype,@compression)");
            cmd.AddParameter("@compression", _compression);
            cmd.AddParameter("@lastaccess", new DateTime(1980, 1, 1, 0, 0, 0));
            cmd.AddParameter("@filename", _filename);
            cmd.AddParameter("@extension", _extension);
            cmd.AddParameter("@contenttype", _contenttype);
            cmd.AddParameter("@siteid", _siteid);
            cmd.AddParameter("@assetid", _assetid);
            dbc.ExecuteCommand(cmd);
        }

        public void Upload(System.Web.UI.WebControls.FileUpload Upload)
        {
            _contenttype = Upload.PostedFile.ContentType.ToLower();
            System.IO.FileInfo info = new System.IO.FileInfo(Upload.PostedFile.FileName);
            _filename = System.IO.Path.GetFileNameWithoutExtension(info.FullName);
            _extension = info.Extension;
            _compression = Settings.SettingsManager.AssetCompression;

            if (!CompressionEnabled)
            {
                Upload.SaveAs(ApplicationPath);
                return;
            }

            FileStream fs = new FileStream(ApplicationPath, FileMode.Create, FileAccess.Write);
            Stream compressStream = GetCompressionStream(fs, CompressionMode.Compress);
            compressStream.Write(Upload.FileBytes, 0, Upload.FileBytes.Length);
            compressStream.Flush();
            compressStream.Close();
            fs.Close();
        }

        public void Delete()
        {
            DataConnection dbc = new DataConnection();
            Command cmd = new Command("DELETE FROM assets WHERE siteid = @siteid AND assetid = @assetid");
            cmd.AddParameter("@siteid", _siteid);
            cmd.AddParameter("@assetid", _assetid);
            dbc.ExecuteCommand(cmd);
            if (System.IO.File.Exists(ApplicationPath)) { System.IO.File.Delete(ApplicationPath); }
        }

        private Size GetProportionalSize(Size szMax, Size szReal)
        {
            int nWidth;
            int nHeight;
            double sMaxRatio;
            double sRealRatio;

            if (szMax.Width < 1 || szMax.Height < 1 || szReal.Width < 1 || szReal.Height < 1)
                return Size.Empty;
            sMaxRatio = (double)szMax.Width / (double)szMax.Height;
            sRealRatio = (double)szReal.Width / (double)szReal.Height;
            if (sMaxRatio < sRealRatio)
            {
                nWidth = Math.Min(szMax.Width, szReal.Width);
                nHeight = (int)Math.Round(nWidth / sRealRatio);
            }
            else
            {
                nHeight = Math.Min(szMax.Height, szReal.Height);
                nWidth = (int)Math.Round(nHeight * sRealRatio);
            }
            return new Size(nWidth, nHeight);
        }

        public Bitmap GetThumbnailImage(int width, int height, Color Background)
        {
            if (!IsImage) { return null; }

            Bitmap bmp = null;
            using (Image img = Image.FromStream(GetStream()))
            {
                Size sz = GetProportionalSize(new Size(width, height), img.Size);
                bmp = new Bitmap(width, height);
                Graphics g = Graphics.FromImage(bmp);
                g.Clear(Background);
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.CompositingQuality = CompositingQuality.HighQuality;
                g.InterpolationMode = InterpolationMode.High;
                System.Drawing.Rectangle rectDestination = new System.Drawing.Rectangle(((width - sz.Width) / 2), ((height - sz.Height) / 2), sz.Width, sz.Height);
                g.DrawImage(img, rectDestination, 0, 0, img.Width, img.Height, GraphicsUnit.Pixel);
            }

            return bmp;
        }

        internal bool CompressionEnabled
        {
            get
            {
                return !string.IsNullOrEmpty(_compression);
            }
        }

        private Stream GetCompressionStream(Stream basestream, CompressionMode Mode)
        {
            string value = _compression;
            if (string.IsNullOrEmpty(value)) { value = Settings.SettingsManager.AssetCompression; }

            switch (value)
            {
                case "gzip":
                    return new GZipStream(basestream, Mode);
                case "deflate":
                    return new DeflateStream(basestream, Mode);
            }

            return null;
        }

        public void UpdateLastAccess()
        {
            DataConnection dbc = new DataConnection();
            Command cmd = new Command("UPDATE assets SET lastaccess = @lastaccess WHERE siteid = @siteid AND assetid = @assetid");
            cmd.AddParameter("@lastaccess", DateTime.Now);
            cmd.AddParameter("@siteid", _siteid);
            cmd.AddParameter("@assetid", _assetid);
            dbc.ExecuteCommand(cmd);
        }
    }
}